package com.java.basis.thread.n8;

import lombok.extern.slf4j.Slf4j;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 使用任务调度线程池来代替 Timer
 * @author wangning
 * @create 2022-02-10 16:30
 */
@Slf4j(topic = "c.TestTimer")
public class TestTimer {
	public static void main(String[] args) {
		//定时执行任务
		ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
		//每隔1s执行一次,如果任务时间较长，会延迟其他任务
		log.debug("start...");
//		pool.scheduleAtFixedRate(() -> {
//			try {
//				Thread.sleep(1000);
//			} catch (InterruptedException e) {
//				e.printStackTrace();
//			}
//
//			log.debug("running");
//		}, 1, 1, TimeUnit.SECONDS);

		//initialDelay-初始延迟时间，也就是第一次执行的时间
		//delay定时任务执行的间隔时间
		//scheduleAtFixedRate，scheduleWithFixedDelay
		//1、scheduleAtFixedRate 方法，顾名思义，它的方法名称的意思是：已固定的频率来执行某项计划(任务)。
		//2、scheduleWithFixedDealy,相对固定的延迟后，执行某项计划。
		//单从它们的字面来看，还是让人困惑，跟TC的管猿似的，文字游戏。
		//还是比较简单明了的描述比较好：第一个方法是固定的频率来执行某项计划，它不受计划执行时间的影响。到时间，它就执行。
		//而第二个方法，相对固定，据鄙人理解，是相对任务的。即无论某个任务执行多长时间，等执行完了，我再延迟指定的时间。也就是第二个方法，它受计划执行时间的影响。
		pool.scheduleWithFixedDelay(() -> {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			log.debug("running");
		}, 1, 1, TimeUnit.SECONDS);
	}

	/**
	 * 使用任务调度延时执行任务，与Timer对比的优势
	 * 1.当某一个任务执行的时间过程，不会阻塞其他任务
	 * 2.当任务发生异常时，不会影响其他任务的执行
	 */
	private static void method02() {
		ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
		pool.schedule(() -> {
			log.debug("task1");
			int i = 1 / 0;
//			try {
//				Thread.sleep(2000);
//			} catch (InterruptedException e) {
//				e.printStackTrace();
//			}

		}, 1, TimeUnit.SECONDS);
		pool.schedule(() -> {
			log.debug("task2");
		}, 1, TimeUnit.SECONDS);
	}

	/**
	 * 使用Timer的时候是串行的，一旦某一个任务执行的时间过长，就会导致后面的任务阻塞
	 * 而且出现异常时，如果没有捕获，就会导致后面的任务也没办法执行
	 */
	private static void method01() {
		Timer timer = new Timer();
		TimerTask task1 = new TimerTask() {
			@Override
			public void run() {
				log.debug("task 1");
				int i = 1 / 0;
//				try {
//					Thread.sleep(2000);
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
			}
		};

		TimerTask task2 = new TimerTask() {
			@Override
			public void run() {
				log.debug("task 2");
			}
		};

		log.debug("start...");
		timer.schedule(task1, 1000);
		timer.schedule(task2, 1000);
	}
}
